package com.yazif.vqa.util;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import com.yazif.vqa.api.wechat.domain.Message;
import com.yazif.vqa.api.wechat.domain.XmlCDATA;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.transform.sax.SAXResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class XmlUtils {

    public static String toXML(Object xml) {
        if (xml != null){
            try {
                JAXBContext context = JAXBContext.newInstance(xml.getClass());
                OutputFormat of = createOutputFormat(xml);

                ByteArrayOutputStream op = new ByteArrayOutputStream();

                XMLSerializer serializer = new XMLSerializer(op, of);
                SAXResult result = new SAXResult(serializer.asContentHandler());

                Marshaller mar = context.createMarshaller();
                mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                mar.marshal(xml, result);

                return op.toString("UTF-8");
            } catch (JAXBException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "";
    }

    public static Object toJavaBean(Class clazz, String xml){
        Object obj = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller um = context.createUnmarshaller();
            obj = um.unmarshal(new ByteArrayInputStream(xml.getBytes("utf-8")));
        }catch (Exception e){
            e.printStackTrace();
        }
        return obj;
    }
    public static Object toJavaBean(Class clazz, File xml){
        Object obj = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller um = context.createUnmarshaller();
            obj = um.unmarshal(xml);
        }catch (Exception e){
            e.printStackTrace();
        }
        return obj;
    }



    private static OutputFormat createOutputFormat(Object xml){
        //配置输出格式
        OutputFormat of = new OutputFormat();

        String[] cdataHandle = getCdataField(xml.getClass());
        if (cdataHandle != null && cdataHandle.length > 0){
            of.setCDataElements(cdataHandle);
        }
        of.setPreserveSpace(true);
        of.setIndenting(true);

        return of;
    }

    private static String[] getCdataField(Class clazz){
        Field[] fields = clazz.getDeclaredFields();
        List<String> cdataFieldList = new ArrayList<>();
        for (Field field : fields){
            if (field.isAnnotationPresent(XmlCDATA.class)){
                String name = field.getAnnotation(XmlElement.class).name();
                if ("##default".equals(name)){
                    name = field.getName();
                }
                name = String.format("^%s", name);
                cdataFieldList.add(name);
            }
        }
        String[] cdataField = new String[cdataFieldList.size()];
        cdataFieldList.toArray(cdataField);
        return cdataField;
    }


    public static void main(String[] args) {
        Message messageTO = (Message) toJavaBean(Message.class, "<xml><ToUserName><![CDATA[1]]></ToUserName><FromUserName><![CDATA[2]]></FromUserName><CreateTime>3</CreateTime><MsgType><![CDATA[4]]></MsgType><MsgId>6</MsgId><Content><![CDATA[5]]></Content></xml>");

        System.out.println(toXML(messageTO));
    }
}
